package com.tbit.main.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbit.common.utils.TraceUtil;
import com.tbit.main.common.JsonResult;
import com.tbit.main.constant.RecoveryLogConstant;
import com.tbit.main.dao.core.AccountDao;
import com.tbit.main.dao.core.MachineDao;
import com.tbit.main.dao.core.StockMachineMapper;
import com.tbit.main.exception.BaseException;
import com.tbit.main.pojo.*;
import com.tbit.main.pojo.VO.StockMachineVO;
import com.tbit.main.service.MachineService;
import com.tbit.main.service.MachineStatusService;
import com.tbit.main.service.RecoveryLogService;
import com.tbit.main.service.StockMachineService;
import com.tbit.main.util.GeoUtil;
import com.tbit.main.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: chen
 * @Description: 车辆入库管理
 * @Date: 创建于 16:50 2023/2/9
 */
@Service
public class StockMachineServiceImpl extends ServiceImpl<StockMachineMapper, StockMachine> implements
        StockMachineService {

    @Autowired
    private StockMachineMapper stockMachineMapper;
    @Autowired
    private MachineService machineService;
    @Autowired
    private RecoveryLogService recoveryLogService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private MachineDao machineDao;
    @Autowired
    private AccountDao accountDao;

    @Override
    public List<StockMachineVO> queryPage(Integer accountId, String userCode, Integer pageNO,
                                          Integer rowCount) {
        Map<String, Object> map = new HashMap<>();
        Account byAccountId = accountDao.getByAccountId(accountId);
        map.put("accountId", accountId);
        map.put("userCode", userCode);
        map.put("start", (pageNO - 1) * rowCount);
        map.put("rowCount", rowCount);
        List<StockMachineVO> stockMachineVOS = stockMachineMapper.queryPage(map);
        List<StockMachineVO> collect = stockMachineVOS.stream().map((stockMachineVO) -> {
            if (stockMachineVO.getWarehouseName() == null || "".equals(stockMachineVO.getWarehouseName())) {
                stockMachineVO.setWarehouseName(byAccountId.getName() + "默认仓库");
            }
            return stockMachineVO;
        }).collect(Collectors.toList());
        return collect;
    }


    @Override
    public List<StockMachineVO> selectByWarehouseId(Integer warehouseId) {
        Map<String, Object> map = new HashMap<>();
        map.put("warehouseId", warehouseId);
        return stockMachineMapper.selectByWarehouseId(map);
    }

    @Override
    public List<StockMachineVO> selectByWarehouseIdS(List<Integer> warehouseId,String userCode, Integer accountId) {
        Account byAccountId = accountDao.getByAccountId(accountId);
        Map<String, Object> map = new HashMap<>();
        map.put("warehouseId", warehouseId);
        map.put("accountId", accountId);
        if (null != userCode && !"".equals(userCode)){
            map.put("userCode", userCode);
            Machine byUseCode = machineDao.getByUseCode(map);
            if (byUseCode != null){
                map.put("machineId", byUseCode.getMachineId());
            }
        }
        List<StockMachineVO> stockMachineVOS = stockMachineMapper.selectByWarehouseIdS(map);
        List<StockMachineVO> collect = stockMachineVOS.stream().map((stockMachineVO) -> {
            if (stockMachineVO.getWarehouseName() == null || "".equals(stockMachineVO.getWarehouseName())) {
                stockMachineVO.setWarehouseName(byAccountId.getName() + "默认仓库");
            }
            return stockMachineVO;
        }).collect(Collectors.toList());
        return collect;
    }
    @Override
    public Integer queryCount(Integer accountId, String userCode) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("userCode", userCode);
        return stockMachineMapper.queryCount(map);
    }

    @Override
    public Integer countByMachineId(Integer machineId) {
        return stockMachineMapper.countByMachineId(machineId);
    }

    @Override
    public void add(String userCode, AccountUser accountUser,String warehouseName,String warehouseId,Integer accountId) {
        /**鉴权*/
        Machine machine = checkauth(userCode, accountUser,accountId);
        QueryWrapper stockWrapper = new QueryWrapper();
        stockWrapper.eq("machineId", machine.getMachineId());
        StockMachine stockMachineDB = getOne(stockWrapper);
        if (stockMachineDB != null) {
            throw new BaseException("StockMachine.is.exist");
        }
        StockMachine stockMachine = new StockMachine();
        stockMachine.setAccountId(machine.getAccountId());
        stockMachine.setAddTime(new Date());
        stockMachine.setMachineId(machine.getMachineId());
        stockMachine.setUserId(accountUser.getAccountUserId());
        stockMachine.setWarehouseName(warehouseName);
        stockMachine.setWarehouseId(warehouseId);
        /**数据入库*/
        save(stockMachine);
        /**存在回收记录需要将回收记录置为已回收*/
        RecoveryLog recoveryLogDB = checkRecoveryLog(machine, accountUser);
        if (recoveryLogDB != null) {
            recoveryLogDB.setStockId(Integer.valueOf(warehouseId));
            recoveryLogDB.setStockName(warehouseName);
            recoveryLogDB.setStockTime(new Date());
            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("recoveryId", recoveryLogDB.getRecoveryId());
            recoveryLogService.update(recoveryLogDB, queryWrapper);
        }else {
            MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
            if (machineStatus != null && machineStatus.getLon() != null && machineStatus.getLat() != null) {
                recoveryLogDB = new RecoveryLog(machine.getAccountId(), machine.getMachineId(), machine.getUserCode(), machine.getMachineNO()
                        , null, machineStatus.getLon(), machineStatus.getLat(), null, "无",
                        RecoveryLogConstant.RECOVERYLOG_STATE_SUCCESS);
                recoveryLogDB.setStockId(Integer.valueOf(warehouseId));
                recoveryLogDB.setStockName(warehouseName);
                recoveryLogDB.setStockTime(new Date());
                recoveryLogDB.setStockUserId(accountUser.getAccountUserId());
                recoveryLogDB.setStockUserName(accountUser.getName());
                recoveryLogService.save(recoveryLogDB);
            }
        }
    }

    @Override
    public void del(String userCode, AccountUser accountUser,Integer accountId) {
        /**鉴权*/
        Machine machine = checkauth(userCode, accountUser,accountId);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("machineId", machine.getMachineId());
        queryWrapper.eq("accountId", machine.getAccountId());
        StockMachine stockMachine = getOne(queryWrapper);
        if (stockMachine != null) {
            remove(queryWrapper);
            RecoveryLog recoveryLog = recoveryLogService.getByAccountId(machine.getAccountId(), machine.getMachineId(), RecoveryLogConstant.RECOVERYLOG_STATE_SUCCESS);
            if (Objects.nonNull(recoveryLog)) {
                recoveryLog.setState(RecoveryLogConstant.RECOVERYLOG_STATE_FALSE);
                recoveryLog.setOutStockTime(new Date());
                recoveryLog.setOutStockUserId(accountUser.getAccountUserId());
                recoveryLog.setOutStockUserName(accountUser.getName());
                QueryWrapper recoveryLogQueryWrapper = new QueryWrapper();
                recoveryLogQueryWrapper.eq("recoveryId", recoveryLog.getRecoveryId());
                recoveryLogService.update(recoveryLog, recoveryLogQueryWrapper);
            }
        } else {
            throw new BaseException("StockMachine.is.null");
        }
    }

    @Override
    public JsonResult addBatch(List<String> userCodes, AccountUser accountUser,String warehouseName,String warehouseId,Integer accountId) {
        /**查询回收车辆*/
        Map<String, Object> map = new HashMap<>();
        map.put("userCode", StringUtil.getStringListString(userCodes));
        map.put("state", RecoveryLogConstant.RECOVERYLOG_STATE_DEFALT);
        List<Machine> machines = machineService.getByUserCodes(userCodes);
        List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());
        /**获取车辆id，查询入库车辆，存在返回*/

        Map<String, Object> mapMachineId = new HashMap<>();
        mapMachineId.put("machineId", StringUtil.getListString(machineIds));
        List<StockMachine> existMachines = stockMachineMapper.getByMachineId(mapMachineId);
        if (!existMachines.isEmpty()) {
            return JsonResult.fail(500, existMachines + "已是入库车辆", TraceUtil.getTraceIdByLocal());
        }
        /**批量校验*/
        checkBatchAuth(machines, accountUser, userCodes,accountId);
        List<StockMachine> stockMachines = new ArrayList<>();

        List<RecoveryLog> recoveryLogs = new ArrayList<>();
        List<RecoveryLog> recoveryLogsInsert = new ArrayList<>();
        for (Machine machine : machines) {
//                machineService.authCheck(accountUser, machine.getUserCode());
            StockMachine stockMachine = new StockMachine();
            stockMachine.setAccountId(machine.getAccountId());
            stockMachine.setAddTime(new Date());
            stockMachine.setMachineId(machine.getMachineId());
            stockMachine.setUserId(accountUser.getAccountUserId());
            stockMachine.setWarehouseName(warehouseName);
            stockMachine.setWarehouseId(warehouseId);
            stockMachines.add(stockMachine);
            RecoveryLog recoveryLogDB = checkRecoveryLog(machine, accountUser);
            if (recoveryLogDB != null) {
                recoveryLogDB.setStockId(Integer.valueOf(warehouseId));
                recoveryLogDB.setStockName(warehouseName);
                recoveryLogDB.setStockTime(new Date());
                recoveryLogs.add(recoveryLogDB);
                //如果没有回收记录,直接插入为入库
            } else {
                MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
                if (machineStatus != null && machineStatus.getLon() != null && machineStatus.getLat() != null) {
                    recoveryLogDB = new RecoveryLog(machine.getAccountId(), machine.getMachineId(), machine.getUserCode(), machine.getMachineNO()
                            , null, machineStatus.getLon(), machineStatus.getLat(), null, "无",
                            RecoveryLogConstant.RECOVERYLOG_STATE_SUCCESS);
                    recoveryLogDB.setStockId(Integer.valueOf(warehouseId));
                    recoveryLogDB.setStockName(warehouseName);
                    recoveryLogDB.setStockTime(new Date());
                    recoveryLogDB.setStockUserId(accountUser.getAccountUserId());
                    recoveryLogDB.setStockUserName(accountUser.getName());
                    recoveryLogsInsert.add(recoveryLogDB);
                }
            }
        }
        if (!stockMachines.isEmpty()) {
            saveBatch(stockMachines);
        }
        if (!recoveryLogs.isEmpty()) {
            recoveryLogs.stream().forEach(recoveryLog -> {
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("recoveryId", recoveryLog.getRecoveryId());
                recoveryLogService.update(recoveryLog, queryWrapper);
            });
        }
        for (RecoveryLog recoveryLog : recoveryLogsInsert) {
            recoveryLogService.save(recoveryLog);
        }

        return JsonResult.succ();
    }

    @Override
    public void delBatch(List<String> userCodes, AccountUser accountUser,Integer accountId) {
        List<Machine> machines = machineService.getByUserCodes(userCodes);
        /**批量校验*/
        checkBatchAuth(machines, accountUser, userCodes,accountId);
        List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.in("machineId", machineIds);
        List<StockMachine> stockMachines = list(queryWrapper);
        if (!stockMachines.isEmpty()) {
            List<Integer> ids = stockMachines.stream().map(StockMachine::getBoundId).collect(Collectors.toList());
            QueryWrapper delwrapper = new QueryWrapper();
            delwrapper.in("boundId", ids);
            remove(delwrapper);
        }
        for (Machine machine : machines) {
            RecoveryLog recoveryLog = recoveryLogService.getByAccountId(machine.getAccountId(), machine.getMachineId(), RecoveryLogConstant.RECOVERYLOG_STATE_SUCCESS);
            if (recoveryLog != null) {
                recoveryLog.setState(RecoveryLogConstant.RECOVERYLOG_STATE_FALSE);
                recoveryLog.setOutStockTime(new Date());
                recoveryLog.setOutStockUserId(accountUser.getAccountUserId());
                recoveryLog.setOutStockUserName(accountUser.getName());
                QueryWrapper  recoveryLogQueryWrapper = new QueryWrapper();
                recoveryLogQueryWrapper.eq("recoveryId", recoveryLog.getRecoveryId());
                recoveryLogService.update(recoveryLog, recoveryLogQueryWrapper);
            }
        }
    }

    //批量修改仓库
    @Override
    public void updateBatch(List<String> userCodes, AccountUser accountUser,String warehouseName,String warehouseId) {
        List<Machine> machines = machineService.getByUserCodes(userCodes);
        /**批量校验*/
//        checkBatchAuth(machines, accountUser, userCodes);
        List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.in("machineId", machineIds);
        List<StockMachine> stockMachines = list(queryWrapper);
        if (!stockMachines.isEmpty()) {
            List<Integer> ids = stockMachines.stream().map(StockMachine::getBoundId).collect(Collectors.toList());
            UpdateWrapper<StockMachine> updateWrapper = new UpdateWrapper();
            updateWrapper.in("boundId", ids);
            updateWrapper.set("warehouseName", warehouseName);
            updateWrapper.set("warehouseId", warehouseId);
            update(updateWrapper);
        }
        for (Machine machine : machines) {
            RecoveryLog recoveryLog = recoveryLogService.getByAccountId(machine.getAccountId(), machine.getMachineId(), RecoveryLogConstant.RECOVERYLOG_STATE_SUCCESS);
            if (recoveryLog != null) {
                //换库房修改库房名称和id
                recoveryLog.setStockId(Integer.valueOf(warehouseId));
                recoveryLog.setStockName(warehouseName);
                QueryWrapper  recoveryLogQueryWrapper = new QueryWrapper();
                recoveryLogQueryWrapper.eq("recoveryId", recoveryLog.getRecoveryId());
                recoveryLogService.update(recoveryLog, recoveryLogQueryWrapper);
            }
        }
    }

    /**
     * 回收记录校验处理
     *
     * @param machine
     * @param accountUser
     * @return
     */
    public RecoveryLog checkRecoveryLog(Machine machine, AccountUser accountUser) {
        RecoveryLog recoveryLog = recoveryLogService.getByAccountId(machine.getAccountId(), machine.getMachineId(), RecoveryLogConstant.RECOVERYLOG_STATE_DEFALT);
        if (recoveryLog != null) {
            MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
            if (machineStatus == null || machineStatus.getLon() == null || machineStatus.getLat() == null) {
                log.warn("设备位置为空" + machine.getMachineNO());
                return null;
            }
            RecoveryLog recoveryLogDB = new RecoveryLog();
            recoveryLogDB.setRecoveryId(recoveryLog.getRecoveryId());
            recoveryLogDB.setEndLo(machineStatus.getLon());
            recoveryLogDB.setEndLa(machineStatus.getLat());
//            recoveryLogDB.setEndTime(new Date());
            recoveryLogDB.setStockUserId(accountUser.getAccountUserId());
            recoveryLogDB.setStockUserName(accountUser.getName());
            recoveryLogDB.setState(RecoveryLogConstant.RECOVERYLOG_STATE_SUCCESS);
            recoveryLogDB.setDistance(
                    (int) GeoUtil.getDistance(new Point(recoveryLog.getStartLo(), recoveryLog.getStartLa()), new Point(recoveryLogDB.getEndLo(), recoveryLogDB.getEndLa())));
            return recoveryLogDB;
        }
        return null;
    }

    /**
     * 批量校验
     *
     * @param machines
     * @param accountUser
     */
    @Override
    public void checkBatch(List<Machine> machines, AccountUser accountUser, List<String> userCodes) {
        List<String> existNo = new ArrayList<>();
        for (Machine machine : machines) {
            check(machine.getUserCode(), accountUser);
            existNo.add(machine.getUserCode());
        }
        /**求差集*/
        userCodes.removeAll(existNo);
        if (!userCodes.isEmpty()) {
            throw new BaseException("车辆编号不存在");
        }
    }


    /**
     * 针对于入库和扣押的批量校验
     *
     * @param machines
     * @param accountUser
     */
    @Override
    public void checkBatchAuth(List<Machine> machines, AccountUser accountUser, List<String> userCodes,Integer accountId) {
        List<String> existNo = new ArrayList<>();
        for (Machine machine : machines) {
            checkauth(machine.getUserCode(), accountUser,accountId);
            existNo.add(machine.getUserCode());
        }
        /**求差集*/
        userCodes.removeAll(existNo);
        if (!userCodes.isEmpty()) {
            throw new BaseException("车辆编号不存在");
        }
    }

    @Override
    public List<StockMachine> getByAccountId(Integer accountId, List<Integer> regionId) {
        Map<String, Object> map = new HashMap<>();
        map.put("regionId", regionId);
        map.put("accountId", accountId);
        return stockMachineMapper.getByAccountId(map);
    }

    @Override
    public List<Integer> getAccountIdMachineId(Integer accountId) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        return stockMachineMapper.getAccountIdMachineId(map);
    }

    @Override
    public List<Integer> getAccountIdByMachineId(Integer accountId, List<Integer> machineId) {
        Map<String, Object> map = new HashMap<>();
        map.put("accountId", accountId);
        map.put("machineId", StringUtil.getListString(machineId));
        return stockMachineMapper.getAccountIdByMachineId(map);
    }

    /**
     * 检验
     *
     * @param userCode
     * @param accountUser
     * @return
     */
    public Machine check(String userCode, AccountUser accountUser) {
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }
        machineService.auth(accountUser.getAgents(), machine);
        return machine;
    }


    /**
     * 专门针对与入库和扣押的校验
     *
     * @param userCode
     * @param accountUser
     * @return
     */
    public Machine checkauth(String userCode, AccountUser accountUser,Integer accountId) {
        machineService.authCheck(accountUser,userCode,accountId);
        Machine machine = machineService.getByUseCode(userCode);
        return machine;
    }


    @Override
    public JsonResult checkMachine(String userCode) {
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            stringObjectHashMap.put("status",0);
            stringObjectHashMap.put("msg","车辆不存在");
           return JsonResult.succ(stringObjectHashMap);
        }
        return JsonResult.succ();
    }

    @Override
    public List<Integer> getExist(List<Integer> machineIds) {
        return stockMachineMapper.getExist(machineIds);
    }

    @Override
    public void deleteBatchByMachineList(List<Integer> machineIdList, String remark) {
        LambdaQueryWrapper<StockMachine> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(StockMachine::getMachineId, machineIdList);
        stockMachineMapper.delete(wrapper);
        recoveryLogService.updateBatchByMachineList(machineIdList, RecoveryLogConstant.RECOVERYLOG_STATE_FALSE, remark);
    }
}
